import tinycolor from "./tinycolor.js";
import "./style.css";
export const colorTree = {
  tag: "section",
  className: "color-picker",
  children: [
    {
      tag: "div",
      className: "picker-head",
      children: [
        {
          tag: "div",
          className: "brightness-icon",
        },
        {
          tag: "div",
          className: "color-string",
          value: "#ff0000",
        },
        {
          tag: "div",
          className: "picker-head-close",
          value: "×",
        },
      ],
    },
    {
      tag: "div",
      className: "picker-body",
      children: [
        {
          tag: "div",
          className: "saturation-box",
          children: [
            {
              tag: "div",
              className: "saturation-picker",
            },
            {
              tag: "canvas",
              className: "saturation-canvas",
            },
          ],
        },
        {
          tag: "div",
          className: "strips",
          children: [
            {
              tag: "div",
              className: "strip alpha",
              children: [
                {
                  tag: "div",
                  className: "slider",
                },
              ],
            },
            {
              tag: "div",
              className: "strip hue",
              children: [
                {
                  tag: "div",
                  className: "slider",
                },
              ],
            },
          ],
        },
      ],
    },
    {
      tag: "div",
      className: "picker-footer",
      children: [
        {
          tag: "span",
          className: "picker-footer-label",
          value: "最近使用",
        },
        {
          tag: "div",
          className: "picker-footer-body",
          children: [
            {
              tag: "span",
              className: "picker-footer-block",
              bgColor: "#BC0010"
            },
            {
              tag: "span",
              className: "picker-footer-block",
              bgColor: "#FA0019"
            },
            {
              tag: "span",
              className: "picker-footer-block",
              bgColor: "#FCC028"
            },
            {
              tag: "span",
              className: "picker-footer-block",
              bgColor: "#FDFF31"
            },
            {
              tag: "span",
              className: "picker-footer-block",
              bgColor: "#94D156"
            },
            {
              tag: "span",
              className: "picker-footer-block",
              bgColor: "#20B153"
            },
            {
              tag: "span",
              className: "picker-footer-block",
              bgColor: "#2DB0EE"
            },
            {
              tag: "span",
              className: "picker-footer-block",
              bgColor: "#1D70BE"
            },
            {
              tag: "span",
              className: "picker-footer-block",
              bgColor: "#07205F"
            },
            {
              tag: "span",
              className: "picker-footer-block",
              bgColor: "#702E9E"
            },
            
          ],
        },
      ],
    },
  ],
};

export class KfColorPicker {
  root = document.documentElement;
  constructor(el, options) {
    this.colorDom = null;
    this.color = '#ff0000';
    this.currentColor = null;
    this.onColorChange = null;
    this.colorTypes = ['hex', 'rgb', 'hsl', 'hsv'];
  }
  initColorPicker(setting = {el: document.body,width:240}) {
    this.colorDom = this.createColorElements(colorTree);
    setting.el ? setting.el.appendChild(this.colorDom):document.body.appendChild(this.colorDom);
    this.root.style.setProperty("--picker-width", setting.width ? setting.width +'px' : '240px')
    this.start();
    this.showColorPicker(false);
    this.eventBindingHandle();
    return this.colorDom;
  }
  createColorElements(domTree) {
    let el = null;
    for (const key in domTree) {
      if (key === "tag") {
        el = document.createElement(domTree[key]);
      } else if (key === "className" && el instanceof HTMLElement) {
        el.setAttribute('class', domTree[key])
      } else if (key === "value" && el instanceof HTMLElement) {
        el.innerText = domTree[key];
      } else if (key === "bgColor" && el instanceof HTMLElement) {
        el.setAttribute("style", `background-color: ${domTree[key]}`);
      } 
      else if (domTree.hasOwnProperty(key) && key === "children") {
        domTree[key].forEach(child => {
          let el2 = this.createColorElements(child);
          el.appendChild(el2);
        })
      }
    }
    return el;
  }

  start() {
    this.canvas = document.querySelector('.saturation-canvas'); // 画布
    this.colorBox = document.querySelector('.saturation-box');  // 画布盒子
    this.picker = this.colorBox.querySelector('.saturation-picker');  // 选择器指针
    this.alphaStrip = document.querySelector('.strip.alpha');  // 透明带
    this.alphaSlider = this.alphaStrip.querySelector('.slider');  // 透明滑块
    this.hueStrip = document.querySelector('.strip.hue'); // 色调带
    this.hueSlider = this.hueStrip.querySelector('.slider');  // 色调滑块

    this.head = document.querySelector('.picker-head'); // 头部
    this.colorString = document.querySelector('.color-string');  // 头部颜色值
    this.brightnessIcon = document.querySelector('.brightness-icon');  // 亮度icon

    this.closeDOM = document.querySelector('.picker-head-close');

    // 饱和度处理函数
    this.pickingSaturationHandler = null;
    // 色调处理函数
    this.pickingHueHandler = null;
    // 透明度处理函数
    this.pickingAlphaHandler = null;

    this.saturation = 1; // 饱和度 0-1
    this.brightness = 1; // 亮度 0-1
    this.alpha = 1; // 透明度 0-1
    this.hue = 0; // 色调 0-360deg
    this.currentColorType = 'hex'; // 当前颜色类型

    this.drawSaturationPicker();

  }
  // 绘制调色面板
  drawSaturationPicker() {
    const ctx = this.canvas.getContext('2d');
    ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
    ctx.fillStyle = tinycolor(`hsv ${this.hue} 1 1`).toHexString();
    ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);

    const whiteGradient = ctx.createLinearGradient(0, 0, this.canvas.width, 0);
    whiteGradient.addColorStop(0, '#fff');
    whiteGradient.addColorStop(1, 'transparent');
    ctx.fillStyle = whiteGradient;
    ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);

    const blackGradient = ctx.createLinearGradient(0, 0, 0, this.canvas.height);
    blackGradient.addColorStop(0, 'transparent');
    blackGradient.addColorStop(1, '#000');
    ctx.fillStyle = blackGradient;
    ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
  }
  // 设置颜色字符串
  setColorString() {
    let str = '';
    const opaque = this.currentColor.getAlpha() === 1;
    switch (this.currentColorType) {
      case 'hex':
        str = opaque ? this.currentColor.toHexString() : this.currentColor.toHex8String();
        break;
      case 'rgb':
        str = this.currentColor.toRgbString();
        break;
      case 'hsl':
        str = this.currentColor.toHslString();
        break;
      case 'hsv':
        str = this.currentColor.toHsvString();
        break;
      default:
        break;
    }
    if (str) {
      this.colorString.textContent = str;
    }
  }
  // 设置当前颜色
  setCurrentColor(colorString) {
    if (colorString) {
      this.currentColor = tinycolor(colorString);
    } else {
      this.currentColor = tinycolor(`hsva(${this.hue},${this.saturation * 100}%, ${this.brightness * 100}%, ${this.alpha})`);
    }
    this.color = this.currentColor.toHex8String();
    if (this.onColorChange) {
      this.onColorChange(this.currentColor.toHex8String());
    }
    this.head.style.backgroundColor = this.currentColor.toHex8String();
    this.setColorString();
    const isBgDark = this.brightness < 0.5 || this.alpha < 0.5;
    this.colorString.style.color = isBgDark ? '#fff' : '#000';
    this.brightnessIcon.style.filter = isBgDark ? 'invert(1)' : 'invert(0)';
    document.documentElement.style.setProperty('--color', this.color);
  }
  // 色调面板mousemove
  handleMouseMove(target, callback, onHanlerCreate) {
    const rect = target.getBoundingClientRect();
    const { left, top, width, height } = rect;

    const handler = e => {
      const { clientX, clientY } = e;
      let x = clientX - left;
      let y = clientY - top;
      let xRatio, yRatio;
      if (x <= 0) {
        xRatio = 0;
        x = 0;
      } else if (x > width) {
        xRatio = 1;
        x = width;
      } else {
        xRatio = x / width;
      }

      if (y <= 0) {
        yRatio = 0;
        y = 0;
      } else if (y > height) {
        yRatio = 1;
        y = height;
      } else {
        yRatio = y / height;
      }
      callback({
        x,
        y,
        xRatio,
        yRatio
      });
    }

    onHanlerCreate(handler);
    window.addEventListener('mousemove', handler);
  }
  // color picker组件显示和隐藏
  showColorPicker(isShow, pos = { x: 100, y: 200 }) {
    if (isShow) {
      this.colorDom.setAttribute('style', 'display: flex');
      this.colorDom.style.left = pos.x - 200  + 'px';
      this.colorDom.style.top = pos.y + 120 + 'px';
    } else {
      this.colorDom.setAttribute('style', 'display: none');
    }
  }
  // mousedown设置颜色
  setColorForMousedown(target, event) {
    const rect = target.getBoundingClientRect();
    const { left, top, width, height } = rect;
    let x, y, xRatio, yRatio;
    x = event.clientX - left; xRatio = (x / width); y = event.clientY - top; yRatio = (y / height);
    return { x, y, xRatio, yRatio };
  }
  // 根据color 求出hueStrip位置
  setPosForColor(bgStr) {
    this.currentColor = tinycolor(bgStr);
    const rect = this.hueStrip.getBoundingClientRect();
    const { width, height } = rect;
    let hsvaStr = this.currentColor.toHsvString();
    let hsvaArr = hsvaStr.substring(hsvaStr.indexOf('(') + 1, hsvaStr.indexOf(')')).split(',').map(it => parseInt(it));
    [this.hue, this.saturation, this.brightness] = hsvaArr;
    this.saturation /= 100; this.brightness /= 100;
    let hueX = this.hue / 360 * width;let pickerX = this.saturation  * width;let pickerY = (1 - this.brightness) * height;
    this.hueSlider.style.left = hueX + 'px';
    this.picker.style.left = pickerX + 'px';
    this.picker.style.top = pickerY + 'px';
    this.setCurrentColor();
    this.drawSaturationPicker();
    return { hueX, pickerX, pickerY };
  }
  // 事件注册中心
  eventBindingHandle() {
    // 关闭color picker 的icon事件
    this.closeDOM.addEventListener('click', e => {
      this.showColorPicker(false);
    })
    // color
    this.colorString.addEventListener('click', e => {
      let index = this.colorTypes.indexOf(this.currentColorType);
      if (index < this.colorTypes.length - 1) {
        index++;
      } else {
        index = 0;
      }
      this.currentColorType = this.colorTypes[index];
      this.setColorString();
    });
    this.colorBox.addEventListener('mousedown', e => {

      let { x, y, xRatio, yRatio } = this.setColorForMousedown(this.colorBox, e);
      this.picker.style.left = x + 'px';
      this.picker.style.top = y + 'px';
      this.saturation = xRatio;
      this.brightness = 1 - yRatio;
      this.setCurrentColor();

      this.handleMouseMove(
        this.colorBox,
        ({ x, y, xRatio, yRatio }) => {
          this.picker.style.left = x + 'px';
          this.picker.style.top = y + 'px';
          this.saturation = xRatio;
          this.brightness = 1 - yRatio;
          this.setCurrentColor();
        },
        (handler) => {
          this.pickingSaturationHandler = handler;
        }
      )
    });

    window.addEventListener('mouseup', e => {
      window.removeEventListener('mousemove', this.pickingSaturationHandler);
    });

    this.alphaStrip.addEventListener('mousedown', e => {
      let { x, y, xRatio, yRatio } = this.setColorForMousedown(this.alphaStrip, e);
      this.alphaSlider.style.left = x + 'px';
      this.alpha = 1 - xRatio;
      this.setCurrentColor();

      this.handleMouseMove(
        this.alphaStrip,
        ({ x, xRatio }) => {
          this.alphaSlider.style.left = x + 'px';
          this.alpha = 1 - xRatio;
          this.setCurrentColor();
        },
        (handler) => {
          this.pickingAlphaHandler = handler;
        }
      )
    });

    window.addEventListener('mouseup', e => {
      window.removeEventListener('mousemove', this.pickingAlphaHandler);
    });
    this.hueStrip.addEventListener('mousedown', e => {
      let { x, y, xRatio, yRatio } = this.setColorForMousedown(this.hueStrip,e);
      this.hueSlider.style.left = x + 'px';
      this.hue = xRatio * 360;
      this.setCurrentColor();
      this.drawSaturationPicker();

      this.handleMouseMove(
        this.hueStrip,
        ({ x, xRatio }) => {
          this.hueSlider.style.left = x + 'px';
          this.hue = xRatio * 360;
          console.log(this.hue);
          this.setCurrentColor();
          this.drawSaturationPicker();
        },
        (handler) => {
          this.pickingHueHandler = handler;
        }
      )
    });

    window.addEventListener('mouseup', e => {
      window.removeEventListener('mousemove', this.pickingHueHandler);
    });

    let commonlyColor = document.querySelectorAll(".picker-footer-body")[0];
    commonlyColor.addEventListener("mousedown", evt => {
      let targetStyle = getComputedStyle(evt.target);
      let bgStr = targetStyle.getPropertyValue("background-color");
      this.setPosForColor(bgStr);
    })
  }
}

const colorPicker = new KfColorPicker();
colorPicker.initColorPicker({width: 300});
export { colorPicker ,} 
